<template>
  <div class="app-container"> <!--app容器-->
    <div class="filter-container"> <!--过滤部分(条件搜索,添加,导出,新增一列显示)-->
      <el-input v-model="listQuery.title" placeholder="姓名" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
      <!--姓名条件搜索-->
      <!--placeholder:占位符-->
      <!--@keyup.enter.native="handleFilter":回车就会执行handleFilter函数,进行搜索-->
      <el-select v-model="listQuery.importance" placeholder="Imp" clearable style="width: 90px" class="filter-item"> <!--级别选择-->
        <!--Select选择器-->
        <!--clearable:可将选择器清空。需要注意的是，clearable属性仅适用于单选-->
        <el-option v-for="item in importanceOptions" :key="item" :label="item" :value="item" />
      </el-select>
      <el-select v-model="listQuery.type" placeholder="Type" clearable class="filter-item" style="width: 130px"> <!--类型选择;参照级别选择-->
        <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name+'('+item.key+')'" :value="item.key" />
      </el-select>
      <el-select v-model="listQuery.sort" style="width: 140px" class="filter-item" @change="handleFilter"> <!--id升序/降序-->
        <el-option v-for="item in sortOptions" :key="item.key" :label="item.label" :value="item.key" />
      </el-select>
      <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter"> <!--搜索按钮-->
        搜索
      </el-button>
      <!--v-waves:点击当前元素触发水波纹效果-->
      <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate"> <!--添加按钮-->
        添加
      </el-button>
      <el-button v-waves :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload"> <!--导出按钮-->
        导出
      </el-button>
      <el-checkbox v-model="showReviewer" class="filter-item" style="margin-left:15px;" @change="tableKey=tableKey+1"> <!--多选框:添加一列到表格中-->
        reviewer
      </el-checkbox>
      <!--v-model="showReviewer":选中showReviewer为ture,反之为false-->
      <!--@change="tableKey=tableKey+1:每次改变,tableKey都会加1-->
    </div>

    <el-table
      :key="tableKey"
      v-loading="listLoading"
      :data="list"
      border
      fit
      highlight-current-row
      style="width: 100%;"
      @sort-change="sortChange"
    > <!--表格部分-->
      <!--:data="list" : 显示的数据,类型为array-->
      <!--fit(boolean):列的宽度是否自撑开,默认为true-->
      <!--highlight-current-row(boolean):是否要高亮当前行,默认为false-->
      <!--@sort-change:当表格的排序条件发生变化的时候会触发该事件;改变列表的排序就会执行sortChange方法-->
      <el-table-column label="ID" prop="id" sortable="custom" align="center" width="80" :class-name="getSortClass('id')">
        <!--id列-->
        <!--class-name:列的className;它有什么作用???-->
        <template slot-scope="{row}">
          <span>{{ row.id }}</span>
        </template>
      </el-table-column>
      <el-table-column label="Date" width="150px" align="center"> <!--日期时间列-->
        <template slot-scope="{row}">
          <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
          <!--row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}'):这种把时间格式化的书写方式也是叼-->
          <!--|:管道符号,将前面的数据流向后面处理(猜测)-->
        </template>
      </el-table-column>
      <el-table-column label="Title" min-width="150px"> <!--标题列-->
        <template slot-scope="{row}">
          <span class="link-type" @click="handleUpdate(row)">{{ row.title }}</span> <!--单击后,弹出编辑对话框-->
          <el-tag>{{ row.type | typeFilter }}</el-tag> <!--type为属性名,返回对应的属性值-->
        </template>
      </el-table-column>
      <el-table-column label="Author" width="110px" align="center"> <!--作者列-->
        <template slot-scope="{row}">
          <span>{{ row.author }}</span>
        </template>
      </el-table-column>
      <el-table-column v-if="showReviewer" label="Reviewer" width="110px" align="center"> <!--根据showReviewer的值决定是否显示该列-->
        <template slot-scope="{row}">
          <span style="color:red;">{{ row.reviewer }}</span>
        </template>
      </el-table-column>
      <el-table-column label="Imp" width="80px"> <!--级别列-->
        <template slot-scope="{row}">
          <svg-icon v-for="n in + row.importance" :key="n" icon-class="star" class="meta-item__icon" /> <!--根据importance来显示icon图标的数量-->
        </template>
      </el-table-column>
      <el-table-column label="Readings" align="center" width="95"> <!--阅读量-->
        <template slot-scope="{row}">
          <span v-if="row.pageviews" class="link-type" @click="handleFetchPv(row.pageviews)">{{ row.pageviews }}</span> <!--单击弹出对话框-->
          <span v-else>0</span>
        </template>
      </el-table-column>
      <el-table-column label="Status" class-name="status-col" width="100"> <!--状态列-->
        <template slot-scope="{row}">
          <el-tag :type="row.status | statusFilter">
            {{ row.status }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="Actions" align="center" width="230" class-name="small-padding fixed-width"> <!--操作列-->
        <template slot-scope="{row,$index}">
          <el-button type="primary" size="mini" @click="handleUpdate(row)"> <!--编辑按钮-->
            编辑
          </el-button>
          <el-button v-if="row.status!='published'" size="mini" type="success" @click="handleModifyStatus(row,'published')"> <!--发表按钮-->
            发表
          </el-button>
          <el-button v-if="row.status!='draft'" size="mini" @click="handleModifyStatus(row,'draft')"> <!--草稿按钮-->
            草稿
          </el-button>
          <el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="handleDelete(row,$index)">
            <!--删除按钮-->
            <!--$index:当前行下标-->
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
    <!--分页栏-->
    <!--:total="total";绑定总条目数-->
    <!--修饰符sync的功能是:当一个子组件改变了一个 prop 的值时，这个变化也会同步到父组件中所绑定-->
    <!--:page.sync="listQuery.page";意味这listQuery.page随当前元素的page特性值变化而变化-->
    <!--:limit.sync="listQuery.limit";参考:page.sync-->
    <!--@pagination="getList";子组件调整每页显示记录数和改变当前页时都会出发该事件;获取列表数据-->
    <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
      <!--表单编辑对话框-->
      <!--el-dialog(对话框):在保留当前页面状态的情况下，告知用户并承载相关操作-->
      <!--title(string):Dialog的标题,也可通过具名slot(见下表)传入-->
      <!--textMap[dialogStatus]:获取对象属性值,对象名[属性名]-->
      <!--visible:是否显示 Dialog，支持 .sync 修饰符-->
      <el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;">
        <!--数据表单-->
        <!--rules(object):表单验证规则-->
        <el-form-item label="Type" prop="type">
          <!--类型-->
          <!--label(string):标签文本-->
          <!--prop(string):指定该项输入映射到数据对象的属性种;表单域 model字段，在使用 validate、resetFields 方法的情况下，该属性是必填的;传入 Form 组件的 model 中的字段-->
          <el-select v-model="temp.type" class="filter-item" placeholder="Please select">
            <!--el-select:Select 选择器;当选项过多时，使用下拉菜单展示并选择内容。-->
            <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="Date" prop="timestamp"> <!--日期-->
          <el-date-picker v-model="temp.timestamp" type="datetime" placeholder="Please pick a date" />
          <!--el-date-picker(DatePicker 日期选择器)-->
          <!--value / v-model:绑定值;类型:date(DatePicker) / array(DateRangePicker))-->
          <!--type(string):显示类型,日期显示的类型,可选值(year/month/date/dates/ week/datetime/datetimerange/ daterange/monthrange)-->
        </el-form-item>
        <el-form-item label="Title" prop="title"> <!--标题-->
          <el-input v-model="temp.title" />
        </el-form-item>
        <el-form-item label="Status"> <!--状态-->
          <el-select v-model="temp.status" class="filter-item" placeholder="Please select">
            <el-option v-for="item in statusOptions" :key="item" :label="item" :value="item" />
          </el-select>
        </el-form-item>
        <el-form-item label="Imp"> <!--级别-->
          <el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;" />
          <!--el-rate:Rate 评分-->
          <!--colors(array/object):icon 的颜色。若传入数组，共有 3 个元素，为 3 个分段所对应的颜色；若传入对象，可自定义分段，键名为分段的界限值，键值为对应的颜色-->
          <!--max(number):最大分值-->
        </el-form-item>
        <el-form-item label="Remark"> <!--备注-->
          <el-input v-model="temp.remark" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="Please input" />
          <!--v-model(number):绑定值-->
          <!--autosize(boolean / object):自适应内容高度，只对 type="textarea" 有效，可传入对象，如，{ minRows: 2, maxRows: 6 }-->
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer"> <!--插槽???-->
        <el-button @click="dialogFormVisible = false">
          取消
        </el-button>
        <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">
          确认
        </el-button>
      </div>
    </el-dialog>

    <el-dialog :visible.sync="dialogPvVisible" title="阅读统计"> <!--浏览量对话框-->
      <el-table :data="pvData" border fit highlight-current-row style="width: 100%"> <!--表格组件会从绑定的数据源中匹配列,自动将所有信息都显示出来-->
        <el-table-column prop="key" label="渠道" />
        <el-table-column prop="pv" label="阅读量" />
      </el-table>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="dialogPvVisible = false">确认</el-button> <!--点击就关闭对话框-->
      </span>
    </el-dialog>
  </div>
</template>

<script>
import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article'
import waves from '@/directive/waves' // waves directive(水波纹指令)
import { parseTime } from '@/utils' // 位于utils/index.js
import Pagination from '@/components/Pagination' // secondary package based on el-pagination(基于elm分页的二级包装)

const calendarTypeOptions = [ // key-value映射
  { key: 'CN', display_name: 'China' },
  { key: 'US', display_name: 'USA' },
  { key: 'JP', display_name: 'Japan' },
  { key: 'EU', display_name: 'Eurozone' }
]

// arr to obj, such as { CN : "China", US : "USA" }
const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => { // calendar Type Options(日历类型键值);将calendarTypeOptions数组转化为对象;reduce()理解见JS数组reduce()方法详解及高级技巧
  acc[cur.key] = cur.display_name // 声明并赋值一个属性
  return acc
}, {})

export default {
  name: 'ComplexTable',
  components: { Pagination },
  directives: { waves }, // 注册或获取全局指令
  filters: {
    statusFilter(status) { // 根据status返回对应的标签类型值
      const statusMap = {
        published: 'success',
        draft: 'info',
        deleted: 'danger'
      }
      return statusMap[status]
    },
    typeFilter(type) { // 返回属性值
      return calendarTypeKeyValue[type] // type为属性名,返回对应的属性值
    }
  },
  data() {
    return {
      tableKey: 0,
      list: null, // 列表
      total: 0, // 总记录数
      listLoading: true,
      listQuery: { // 列表搜索
        page: 1, // 当前页
        limit: 20, // 每页显示的记录数
        importance: undefined, // 级别搜索(重要性)
        title: undefined, // 标题搜索
        type: undefined, // 类型搜索
        sort: '+id' // 表示安装id升序排列
      },
      importanceOptions: [1, 2, 3], // 级别数组
      calendarTypeOptions,
      sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
      statusOptions: ['published', 'draft', 'deleted'], // 表格状态可选的值
      showReviewer: false,
      temp: { // 添加一行新记录的模板
        id: undefined, // 默认未空
        importance: 1, // 默认级别为1
        remark: '', // 默认为空
        timestamp: new Date(), // 默认为当前时间
        title: '', // 标题默认为空
        type: '', // 类型默认为空
        status: 'published' // 状态默认为published(已发布)
      },
      dialogFormVisible: false, // 对话框可见
      dialogStatus: '', // 根据会话状态,来确定对话框标题标题
      textMap: { // 对话框标题,传入update,标题为Edit;传入create,标题为Create
        update: 'Edit',
        create: 'Create'
      },
      dialogPvVisible: false,
      pvData: [], // 浏览量数组
      rules: { // ele表单验证规则对象
        type: [{ required: true, message: 'type is required', trigger: 'change' }], // type(表单的v-model绑定属性)
        timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
        title: [{ required: true, message: 'title is required', trigger: 'blur' }]
      },
      downloadLoading: false
    }
  },
  created() {
    this.getList()
  },
  methods: {
    getList() { // 获取列表
      this.listLoading = true // 打开列表加载动画
      fetchList(this.listQuery).then(response => {
        this.list = response.data.items // 列表赋值
        this.total = response.data.total // 标题赋值

        // Just to simulate the time of the request(只是为了模拟请求时间)
        setTimeout(() => { // 延迟执行函数
          this.listLoading = false
        }, 1.5 * 1000)
      })
    },
    handleFilter() { // 更新列表
      this.listQuery.page = 1 // 当前页置为第一页
      this.getList()
    },
    handleModifyStatus(row, status) { // 提示操作信息,给status进行赋值
      this.$message({
        message: '操作Success',
        type: 'success'
      })
      row.status = status
    },
    sortChange(data) { // 当表格的排序条件发生变化的时候会触发该事件,执行该方法
      const { prop, order } = data // prop是列名字符串,order是升降序字符串
      if (prop === 'id') { // 如果属性为id
        this.sortByID(order)
      }
    },
    sortByID(order) {
      if (order === 'ascending') { // 如果是升序
        this.listQuery.sort = '+id' // 设置为升序标志
      } else {
        this.listQuery.sort = '-id' // 反之设置为降序标志
      }
      this.handleFilter() // 更新列表
    },
    resetTemp() { // 对添加记录的模板进行赋值
      this.temp = {
        id: undefined,
        importance: 1,
        remark: '',
        timestamp: new Date(),
        title: '',
        status: 'published',
        type: ''
      }
    },
    handleCreate() { // 添加一条新的记录
      this.resetTemp() // 临时重置
      this.dialogStatus = 'create' // 会话状态置为create
      this.dialogFormVisible = true // 对话框设置为可见
      this.$nextTick(() => { // $nextTick:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法，获取更新后的 DOM
        this.$refs['dataForm'].clearValidate() // 清楚会话框的验证???
      })
    },
    createData() { // 创建一条新的记录
      this.$refs['dataForm'].validate((valid) => { // validate方法:对整个表单进行校验的方法，参数为一个回调函数。该回调函数会在校验结束后被调用，并传入两个参数：是否校验成功和未通过校验的字段。若不传入回调函数，则会返回一个 promise;参数:Function(callback: Function(boolean, object));valid:是否验证成功
        if (valid) { // 验证成功
          this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id(模拟一个id)
          this.temp.author = 'vue-element-admin' // 设置作者
          createArticle(this.temp).then(() => { // 这就是一个无返回值的post请求(毕竟没有后端嘛)
            this.list.unshift(this.temp) // 把新增加的记录添加到表头
            this.dialogFormVisible = false
            this.$notify({ // 弹出成功的通知
              title: 'Success',
              message: '记录添加成功!',
              type: 'success',
              duration: 2000
            })
          })
        }
      })
    },
    handleUpdate(row) { // 编辑一行记录
      this.temp = Object.assign({}, row) // copy obj;更新模板;使用该行记录赋值给模板
      this.temp.timestamp = new Date(this.temp.timestamp) // 用Date格式化时间
      this.dialogStatus = 'update' // 设置对话框状态为更新
      this.dialogFormVisible = true // 设置对话框可见
      this.$nextTick(() => { // 数据更新后,清除表单验证,不知道啥意思???
        this.$refs['dataForm'].clearValidate()
      })
    },
    updateData() { // 更新一条记录
      this.$refs['dataForm'].validate((valid) => { // valid标记表格数据是否验证成功
        if (valid) { // 如果表单数据验证成功
          const tempData = Object.assign({}, this.temp) // 含义:把temp赋值给tempData
          tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464(将2017年11月30日星期四16:41:05 GMT + 0800（CST）更改为1512031311464);计算将数据转化为毫秒数来表示
          updateArticle(tempData).then(() => {
            const index = this.list.findIndex(v => v.id === this.temp.id) // 找到记录的id值
            this.list.splice(index, 1, this.temp) // 使用temp记录替换list中的该记录
            this.dialogFormVisible = false
            this.$notify({
              title: 'Success',
              message: '记录更新成功!',
              type: 'success',
              duration: 2000
            })
          })
        }
      })
    },
    handleDelete(row, index) { // 删除第index行
      this.$notify({ // 这个是element ui通知组件
        title: 'Success',
        message: 'Delete Successfully',
        type: 'success',
        duration: 2000 // 持续时间
      })
      this.lspliceist.splice(index, 1) // 删除下标为index的元素,只删除一个,返回改变后的数组
    },
    handleFetchPv(pv) { // 弹出显示阅读量的对话框,参数是阅读数据
      fetchPv(pv).then(response => { // 返回浏览量数组
        this.pvData = response.data.pvData // 浏览量数组赋值
        this.dialogPvVisible = true // 浏览量对话框可见
      })
    },
    handleDownload() { // excel导出
      this.downloadLoading = true
      import('@/vendor/Export2Excel').then(excel => { // excel代表Export2Excel这个文件,要使用该文件中的方法就需要通过excel(猜测),可以将excel理解为Export2Excel的形式类名
        const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
        const filterVal = ['timestamp', 'title', 'type', 'importance', 'status'] // 需要导出的列名数组
        const data = this.formatJson(filterVal) // 格式化后的表格记录
        excel.export_json_to_excel({ // 从json中导出excel
          header: tHeader, // ???
          data,
          filename: 'table-list' // 文件名
        })
        this.downloadLoading = false
      })
    },
    formatJson(filterVal) { // 对timestamp列进行处理
      return this.list.map(v => filterVal.map(j => { // v表示表格的一行记录;j表示一个要导出的列名
        if (j === 'timestamp') { // 如果该列是timestamp列
          return parseTime(v[j]) // 返回字符串形式的日期
        } else { // 非timestamp列不做处理
          return v[j] // 非日期的原样返回即可
        }
      }))
    },
    getSortClass: function(key) {
      const sort = this.listQuery.sort // '+id'或者其他
      return sort === `+${key}` ? 'ascending' : 'descending' // 匹配成功返回ascending,反之返回descending
    }
  }
}
</script>
